/*
 * Copyright 2007 Google Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

/**
 * The applet with text socket functionality that has external interface for 
 * JavaScript.
 *
 * Unfortunately we cannot use "fscommand" instead of "getURL" to execute
 * functions of JavaScript, because it doesn't work on Internet Explorer if
 * the applet is dynamically generated.
 * 
 * @author Aleksey Lagoshin
 */

// The number of characters which can be passed to Java through one "getURL"
MAX_PASSED_DATA = 470;

/* 
Names of JavaScript functions which this applet will execute. Each name of 
function has identifier of this applet in it.
*/
FUNC_CONNECTED = "javascript:flash_" + id + "_onConnect()";
FUNC_CLOSED = "javascript:flash_" + id + "_onClose()";
FUNC_DATA = "javascript:flash_" + id + "_onData";
FUNC_PART = "javascript:flash_" + id + "_onPart";
FUNC_IO_ERROR = "javascript:flash_" + id + "_onIOError";

// A queue for pending data
var pendingData = new Array();
var socket = new XMLSocket();

/*
Loading the security policy file from URL specified by the
"crossdomain" parameter. We cannot determine whether that crossdomain 
is loaded and is correct - Flash doesn't give us such information. If 
crossdomain file is not specified, Flash will not be able to connect 
to a server and will fire onConnect event with "false" success parameter. 
*/
System.security.loadPolicyFile(crossdomain);

// Setting all events dispatchers
socket.onConnect = onConnect;
socket.onClose = onClose;
socket.onData = onData;

// Setting external interface
this.addProperty("crossdomain", getCrossdomain, setCrossdomain);
this.addProperty("connect", getConnect, setConnect);
this.addProperty("close", getClose, setClose);
this.addProperty("send", getSend, setSend);
this.addProperty("ready", getReady, setReady);

/**
 * This method passes the data from pendingData queue to JavaScript. If the
 * first element of queue exceeds MAX_PASSED_DATA constant, this method will
 * pick first [MAX_PASSED_DATA] charcters and will pass it to JavaScript through
 * onPart function to tell JavaScript that this is only a part of data. If the 
 * first element is less than MAX_PASSED_DATA, this method will send that data 
 * through onData function to tell JavaScript that this is the last part of data.
 */
function passData() {
  var aData = pendingData[0];
  if (length(aData) > MAX_PASSED_DATA) {
    pendingData[0] = aData.substr(MAX_PASSED_DATA);
  getURL(FUNC_PART + "('" + aData.substr(0, MAX_PASSED_DATA) + "')");
    return;
  }
  // shift method returns and removes the first element from pendingData queue
  getURL(FUNC_DATA + "('" + pendingData.shift() + "')");
}

/**
 * Flash fires this event after connection attempt, "success" parameter indicates
 * whether this attempt was successful or not.
 *
 * @param success true, if connect attempt is successful
 */
function onConnect(success) {
  if (success)
    getURL(FUNC_CONNECTED);
  else
    getURL(FUNC_IO_ERROR + "('Flash applet could not connect to a remote server, " +
                           "check your connection, a remote server and crossdomain " +
                           "policy file.')");
}

/**
 * Fired if socket connection has been closed.
 */
function onClose() {
  getURL(FUNC_CLOSED);
}

/**
 * Fired if data has been received.
 *
 * @param src received data
 */
function onData(src) {
  // Adds a new element to the end of pendingData array
  pendingData.push(src);
  // Passes a data to JavaScript only if pendingData array doesn't contain other data
  if (pendingData.length == 1) {
    passData();
  }
}

/**
 * External interface function, loads the security policy file from URL 
 * specified by a parameter. We cannot determine whether that crossdomain 
 * is loaded and is correct - Flash doesn't give us such information. If 
 * crossdomain file is not specified, Flash will not be able to connect 
 * to a server and will fire onConnect event with "false" success parameter. 
 */
function setCrossdomain(value) {
  System.security.loadPolicyFile(value);
}

/**
 * External interface function, tries to connect to a server.
 *
 * @param value contains host domain (or IP) and port number divided by semicolon
 */
function setConnect(value) {
  var ipPort = value.split(":");
  socket.connect(ipPort[0], ipPort[1]);
}

/**
 * External interface function, closes socket connection.
 */
function setClose(value) {
  socket.close();
}

/**
 * External interface function, sends data to a server.
 */
function setSend(value) {
  socket.send(value);
}

/**
 * External interface function, indicates that Flash can send a new part of data
 * from pendingData array.
 */
function setReady(value) {
  // The browser is ready now for a new part of data
  if (pendingData.length > 0) {
    passData();
  }
}

function getCrossdomain() {
  return null;
}

function getConnect() {
  return null;
}

function getClose() {
  return null;
}

function getSend() {
  return null;
}

function getReady() {
  return null;
}
